export class CheckError{
    private _errors:CheckErrorInfo[] = [];
    private _paths:Describe[] = [];
    public push(info:Describe):void{
        this._paths.push(info);
    }
    public emit(message:string){
        let item = this._paths[this._paths.length - 1];
        if(!item.message){
            item.message = [];
        }
        item.message.push(message)
    }
    public back(bkInfo:Describe):void{
        let info = this._paths.pop();
        if(bkInfo !== info){
            throw "check回退错误"
        }
    }
    public saveError(){
        this._errors.push(new CheckErrorInfo(this._paths.slice()))        
    }
    public getErrors(){
        return this._errors;
    }
}
export class CheckErrorInfo{
    private _errors:Describe[]
    constructor(errors:Describe[]){
        this._errors = errors;
    }
    valueOf(){
        return this._errors;
    }
    toString(){
        let str = "";
        for(let i = 0;i<this._errors.length;i++){
            let item = this._errors[i];
            str += `[${item.theme}]:${item.describe} ${item.data}\n`
        }
        str = `${this._errors[this._errors.length-1].message.reduce((pre,cur)=>{return pre+cur+"\n"},str + "error: ")}`
        return str;
    }
}
export type Describe = {
    theme:string;
    message?:string[];
    data?:any;
    describe:string;
}
export interface ICheck{
    /**
     * 检测类实现接口
     * @param check check.emit("提交的错误信息")
     * @returns 返回data数据 出现错误时 data会在错误中
     */
    __check__(check?:CheckError):any;
}

export const checkError = new CheckError()
/**
 * 检测装饰器
 * @param theme 主题 
 * @param describe 描述
 * @returns 
 */
export function check(theme:string,describe:string){
    return function(target:new (...args:any)=>ICheck){
        let method:(check:any)=>void = target.prototype["__check__"]
        if(method == undefined){
            throw "未定义 __check__";
        }
        target.prototype["__check__"] = function(){
            let info = {
                theme,
                describe,
                message:null as string[],
                data:null as any,
            }
            checkError.push(info)
            const data = method.call(this,checkError);
            info.data = data;
            if(info.message){
                checkError.saveError()
            }
            checkError.back(info)
        }
    }
}